home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / basics / mdiplayer.win / mdiplayer.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  22.4 KB  |  836 lines

  1. //---------------------------------------------------------------------------------------------------
  2. //    MDIPlayer.c
  3. //
  4. //    A rudimentary MDI movie player application
  5. //  Created Aug 5, 1996 by Brian S. Friedkin
  6. //    Copyright 1996 Apple Computer Inc.
  7. //---------------------------------------------------------------------------------------------------
  8. //
  9. //    Change History (most recent first):
  10. //
  11. //       <2>         03/19/98    rtm        added !IsIconic(hwnd) before call to MCIsPlayerEvent in MovieWndProc
  12. //                                    to fix drawing problems when arranging icons
  13. //       <1>         03/18/98    rtm        added !IsIconic(hwnd) to test in WM_SIZE message processing in MovieWndProc
  14. //                                    to fix sizing problems when minimized; added WM_WINDOWPOSCHANGED processing to
  15. //                                    MovieWndProc to stop movies from playing in minimized windows
  16.  
  17.  
  18. // Macintosh headers
  19. #include "QTML.h"
  20. #include "Movies.h"
  21. #include "Scrap.h"
  22.  
  23. // Windows headers
  24. #include <windows.h>
  25. #include "resource.h"
  26.  
  27. #define kMovieControllerHeight    16
  28. #define    RECT_WIDTH(r)    (r.right-r.left)
  29. #define    RECT_HEIGHT(r)    (r.bottom-r.top)
  30. #define    WM_PUMPMOVIE    (WM_USER+0)
  31.  
  32. long FAR PASCAL FrameWndProc  (HWND, UINT, UINT, LONG) ;
  33. long FAR PASCAL MovieWndProc  (HWND, UINT, UINT, LONG) ;
  34. BOOL            DoOpenMovie();
  35. int                DoIdleMenus(HWND hWnd, HMENU hMenu);
  36. Boolean            MyPlayerFilter(MovieController theController, short action, void *params, long refCon);
  37. void            SizeWindowToMovie(HWND hWnd);
  38. static long        GetWindowBorderWidth(HWND hWnd);
  39. static long        GetWindowMenuHeight(HWND hWnd);
  40. static void        DoCut(HWND);
  41. static void        DoCopy(HWND);
  42. static void        DoPaste(HWND);
  43. static void        DoClear(HWND);
  44. static void        DoUndo(HWND);
  45. static void        DoAbout(void);
  46. static void        CalcWindowMinMaxInfo(HWND theWnd, LPMINMAXINFO lpMinMax);
  47.  
  48. // Data held in each child movie window
  49. typedef struct {
  50.     Movie            m;
  51.     MovieController    mc;
  52.     HWND            hWnd;
  53.     short            resID;
  54.     short            refNum;
  55. } ChildWindowRecord, **ChildWindowHand;
  56.  
  57. HANDLE    ghInst;
  58. HWND    ghWnd;
  59. HWND    ghWndMDIClient;
  60. char    szAppName[20];
  61. char    szChildName[] = "MdiChild";
  62. Rect    gMCResizeBounds;
  63. int        cOpen = 0;
  64. BOOL    gWeAreSizingWindow = 0;
  65. BOOL    gWeAreCreatingWindow = 0;
  66. BOOL    gShuttingDown = FALSE;
  67.  
  68. /* ------------------------------------------------------------- */
  69.  
  70. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
  71.                     LPSTR lpszCmdLine, int nCmdShow)
  72. {
  73.     HANDLE        hAccel ;
  74.     HWND        hwndFrame;
  75.     MSG            msg ;
  76.     WNDCLASSEX    wc;
  77.  
  78.     ghInst = hInstance ;
  79.  
  80.     if (!hPrevInstance) 
  81.     {
  82.         LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName));
  83.         
  84.         // Register the frame window class
  85.         wc.cbSize        = sizeof(WNDCLASSEX);
  86.         wc.style         = CS_HREDRAW | CS_VREDRAW;
  87.         wc.lpfnWndProc   = (WNDPROC)FrameWndProc;
  88.         wc.cbClsExtra    = 0;
  89.         wc.cbWndExtra    = 0;
  90.         wc.hInstance     = hInstance;
  91.         wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
  92.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  93.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  94.         wc.lpszMenuName  = szAppName;
  95.         wc.lpszClassName = szAppName;
  96.         wc.hIconSm       = LoadImage(hInstance,
  97.                                      MAKEINTRESOURCE(IDI_APPICON),
  98.                                      IMAGE_ICON,
  99.                                      16, 16,
  100.                                      0);
  101.         if (!RegisterClassEx(&wc))
  102.         {
  103.             if (!RegisterClass((LPWNDCLASS)&wc.style))
  104.                 return FALSE;
  105.         }
  106.  
  107.         // Register the Movie child window class
  108.         wc.cbSize        = sizeof(WNDCLASSEX);
  109.         wc.style         = 0;
  110.         wc.lpfnWndProc   = (WNDPROC)MovieWndProc;
  111.         wc.cbClsExtra    = 0;
  112.         wc.cbWndExtra    = 0;
  113.         wc.hInstance     = hInstance;
  114.         wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHILDICON));
  115.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  116.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  117.         wc.lpszMenuName  = NULL;
  118.         wc.lpszClassName = szChildName;
  119.         wc.hIconSm       = LoadImage(hInstance,
  120.                                      MAKEINTRESOURCE(IDI_CHILDICON),
  121.                                      IMAGE_ICON,
  122.                                      16, 16,
  123.                                      0);
  124.         if (!RegisterClassEx(&wc))
  125.         {
  126.             if (!RegisterClass((LPWNDCLASS)&wc.style))
  127.                 return FALSE;
  128.         }
  129.     }
  130.  
  131.     // Load accelerators
  132.     hAccel = LoadAccelerators (hInstance, szAppName);
  133.  
  134.     // Initialize QuickTime Media Layer
  135.     InitializeQTML(0);
  136.  
  137.     // Initialize QuickTime
  138.     EnterMovies();
  139.  
  140.     // Create the main frame window
  141.     ghWnd = hwndFrame = CreateWindow (szAppName, szAppName,
  142.                                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  143.                                CW_USEDEFAULT, CW_USEDEFAULT,
  144.                                CW_USEDEFAULT, CW_USEDEFAULT,
  145.                                NULL, NULL, hInstance, NULL) ;
  146.  
  147.     // Show the window
  148.     ShowWindow(hwndFrame, nCmdShow);
  149.     UpdateWindow(hwndFrame);
  150.  
  151.     // Process messages
  152.     while (GetMessage(&msg, NULL, 0, 0))
  153.     {
  154.         if (!TranslateMDISysAccel(ghWndMDIClient, &msg))
  155.             if (!TranslateAccelerator(hwndFrame, hAccel, &msg))
  156.             {
  157.                 TranslateMessage(&msg);
  158.                 DispatchMessage(&msg);
  159.             }
  160.     }
  161.  
  162.     // Clean up
  163.     ExitMovies();
  164.     TerminateQTML();
  165.  
  166.     return msg.wParam;
  167. }
  168.  
  169. /* ------------------------------------------------------------- */
  170.  
  171. long FAR PASCAL FrameWndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
  172. {
  173.     HWND               hwndChild ;
  174.  
  175.     switch (message)
  176.     {
  177.         case WM_CREATE:          // Create the client window
  178.         {
  179.             CLIENTCREATESTRUCT ccs = {0};
  180.  
  181.             ccs.hWindowMenu  = GetSubMenu(GetMenu(hwnd), WINDOWMENU);
  182.             ccs.idFirstChild = IDM_WINDOWCHILD;
  183.  
  184.             // Create the MDI client filling the client area
  185.             ghWndMDIClient = CreateWindow("mdiclient",
  186.                                          NULL,
  187.                                          WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL |
  188.                                          WS_HSCROLL,
  189.                                          0, 0, 0, 0,
  190.                                          hwnd,
  191.                                          (HMENU)0xCAC,
  192.                                          ghInst,
  193.                                          (LPVOID)&ccs);
  194.  
  195.             ShowWindow(ghWndMDIClient, SW_SHOW);
  196.         }
  197.         return 0 ;
  198.  
  199.         case WM_COMMAND:
  200.             switch (LOWORD(wParam))
  201.             {
  202.                 case IDM_FILEOPEN:
  203.                     DoOpenMovie();
  204.                     return 0 ;
  205.  
  206.                 case IDM_FILECLOSE:
  207.                     hwndChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L) ;
  208.                     if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0L))
  209.                         SendMessage (ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0L) ;
  210.                     return 0 ;
  211.  
  212.                 case IDM_EXIT:
  213.                     gShuttingDown = TRUE;
  214.                     SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
  215.                     return 0 ;
  216.  
  217.                 case IDM_WINDOWTILE:
  218.                     SendMessage (ghWndMDIClient, WM_MDITILE, 0, 0L) ;
  219.                     return 0 ;
  220.  
  221.                 case IDM_WINDOWCASCADE:
  222.                     SendMessage (ghWndMDIClient, WM_MDICASCADE, 0, 0L) ;
  223.                     return 0 ;
  224.  
  225.                 case IDM_WINDOWICONS:
  226.                     SendMessage (ghWndMDIClient, WM_MDIICONARRANGE, 0, 0L) ;
  227.                     return 0 ;
  228.  
  229.                 case IDM_WINDOWCLOSEALL:
  230.                     {
  231.                         HWND    hwndT;
  232.             
  233.                         while (hwndT = GetWindow(ghWndMDIClient, GW_CHILD))
  234.                         {
  235.                             // Skip the icon and title windows
  236.                             while (hwndT && GetWindow(hwndT, GW_OWNER))
  237.                                 hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  238.  
  239.                             if (!hwndT) break;
  240.  
  241.                             SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndT, 0L);
  242.                         }
  243.                     }
  244.                     return 0;
  245.  
  246.                 case IDM_ABOUT:
  247.                     DoAbout();
  248.                     return 0;
  249.  
  250.                 default:            // Pass to active child
  251.                     hwndChild = (HWND)SendMessage (ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L) ;
  252.                     if (IsWindow (ghWndMDIClient))
  253.                         SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;
  254.  
  255.                     break ;        // and then to DefFrameProc
  256.             }
  257.             break ;
  258.  
  259.         case WM_INITMENU:
  260.             if (GetMenu(hwnd) == (HMENU)wParam)
  261.                 return DoIdleMenus((HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0), (HMENU)wParam);
  262.             return 1;
  263.  
  264.         case WM_DESTROY :
  265.             PostQuitMessage (0) ;
  266.             return 0 ;
  267.     }
  268.  
  269.     return DefFrameProc (hwnd, ghWndMDIClient, message, wParam, lParam) ;
  270. }
  271.  
  272. /* ------------------------------------------------------------- */
  273.  
  274. long FAR PASCAL MovieWndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
  275. {
  276.     WPARAM            nWidth, nHeight;
  277.     MovieController    mc = 0;
  278.     Movie            m = 0;
  279.     ChildWindowHand    hStorage;
  280.     MSG                msg = {0};
  281.  
  282.     if (hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA))
  283.     {
  284.         mc = (**hStorage).mc;
  285.         m = (**hStorage).m;
  286.     }
  287.  
  288.     // Give the movie controller this message first
  289.     if (!gShuttingDown && mc)
  290.     {
  291.         EventRecord    macEvent;
  292.  
  293.         msg.hwnd = hwnd;
  294.         msg.message = message;
  295.         msg.wParam = wParam;
  296.         msg.lParam = lParam;
  297.         msg.time = 0;
  298.         msg.pt.x = 0;
  299.         msg.pt.y = 0;
  300.  
  301.         // tranlate a windows event to a mac event
  302.         WinEventToMacEvent(&msg, &macEvent);
  303.  
  304.         // pass in a mac event
  305.         if (!IsIconic(hwnd))
  306.             MCIsPlayerEvent(mc, (EventRecord*)&macEvent);
  307.     }
  308.  
  309.     switch (message)
  310.     {
  311.         case WM_CREATE:
  312.             // Tuck away some private storage
  313.             hStorage = (ChildWindowHand)NewHandleClear(sizeof(ChildWindowRecord));
  314.             (**hStorage).hWnd = hwnd;
  315.             SetWindowLong(hwnd, GWL_USERDATA, (LPARAM)hStorage);
  316.  
  317.             // Associate a GrafPort with this window
  318.             CreatePortAssociation(hwnd, NULL, 0);
  319.             break;
  320.  
  321.         case WM_WINDOWPOSCHANGING:
  322.             // Don't show the window until we have created a movie and therefore
  323.             // can properly size the window to contain the movie.
  324.             if (gWeAreCreatingWindow)
  325.             {
  326.                 WINDOWPOS    *lpWindowPos = (WINDOWPOS*)lParam;
  327.                 lpWindowPos->flags &= ~SWP_SHOWWINDOW;
  328.                 return 0;
  329.             }
  330.             break;
  331.  
  332.         case WM_WINDOWPOSCHANGED:
  333.             // If a movie window has become minimized, stop the movie.
  334.             if (IsIconic(hwnd))
  335.                 StopMovie(m);
  336.             break;
  337.  
  338.         case WM_SIZE:
  339.             // Resize the movie and controller to fit the window
  340.             nWidth = LOWORD(lParam);
  341.             nHeight = HIWORD(lParam);
  342.             if (!gWeAreSizingWindow && mc && !IsIconic(hwnd))
  343.             {
  344.                 Rect    r = {0};
  345.                 GrafPtr    port = (GrafPtr)MCGetControllerPort(mc);
  346.                 r.right = nWidth;
  347.                 r.bottom = nHeight;
  348.                 MCSetControllerBoundsRect(mc, &r);
  349.             }
  350.             break;
  351.  
  352.         case WM_PUMPMOVIE:                    // We receive this message only to idle the movie
  353.             break;
  354.  
  355.         case WM_COMMAND:
  356.             {
  357.                 switch(LOWORD(wParam))        // Undo, Cut, Copy, Paste and Clear
  358.                 {
  359.                     case IDM_EDITUNDO:
  360.                         DoUndo(hwnd);
  361.                         break;
  362.  
  363.                     case IDM_EDITCUT:
  364.                         DoCut(hwnd);
  365.                         break;
  366.  
  367.                     case IDM_EDITCOPY:
  368.                         DoCopy(hwnd);
  369.                         break;
  370.  
  371.                     case IDM_EDITPASTE:
  372.                         DoPaste(hwnd);
  373.                         break;
  374.  
  375.                     case IDM_EDITCLEAR:
  376.                         DoClear(hwnd);
  377.                         break;
  378.                 }
  379.             }
  380.             break;
  381.  
  382.         case WM_GETMINMAXINFO:
  383.             CalcWindowMinMaxInfo(hwnd, (LPMINMAXINFO)lParam);
  384.             return 0;
  385.  
  386.         case WM_DESTROY:
  387.             // One less movie open
  388.             --cOpen;
  389.  
  390.             // Dispose movie and controller
  391.             hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);
  392.             if ((**hStorage).refNum) CloseMovieFile((**hStorage).refNum);
  393.  
  394.             // Set a player filter proc to nil before closing it because
  395.             // in some instances it gets called after we shut down.
  396.             if (mc) {
  397.                 MCSetActionFilterWithRefCon(mc, MyPlayerFilter, 0);
  398.                 DisposeMovieController(mc);
  399.             }
  400.             if (m) DisposeMovie(m);
  401.             DisposeHandle((Handle)GetWindowLong(hwnd, GWL_USERDATA));
  402.             SetWindowLong(hwnd, GWL_USERDATA, 0);
  403.  
  404.             // Destroy the port association
  405.             DestroyPortAssociation((CGrafPtr)GetHWNDPort(hwnd));
  406.             return 0;
  407.     }
  408.  
  409.     return DefMDIChildProc (hwnd, message, wParam, lParam);
  410. }
  411.  
  412. /* ------------------------------------------------------------- */
  413.  
  414. BOOL DoOpenMovie()
  415. {
  416.     DWORD            dwVersion;
  417.     FSSpec            fileSpec;
  418.     OSErr            err;
  419.     long            mcFlags;
  420.     short            len, movieRefNum, movieResId;
  421.     char            szPathName[256], szFileName[256];
  422.     Rect            movieBounds;
  423.     ChildWindowHand    hStorage;
  424.     RECT            rcWindow;
  425.     HWND            hWndDesktop;
  426.     HWND            hwndChild = 0;
  427.     Movie            theMovie=0;
  428.     MovieController    theMC=0;
  429.     OPENFILENAME    ofn = {0};
  430.  
  431.     // Present the dialog...
  432.     *szPathName = 0;
  433.     ofn.lStructSize = sizeof(OPENFILENAME);
  434.     ofn.hwndOwner = ghWnd;
  435.     ofn.lpstrFile = (LPSTR)szPathName;
  436.     ofn.nMaxFile  = sizeof(szPathName);
  437.     ofn.lpstrFilter  = "QuickTime Movies (*.mov) \0 *.mov\0All Files (*.*) \0 *.*\0";
  438.     ofn.nFilterIndex = 1;
  439.     ofn.lpstrInitialDir = NULL;
  440.     ofn.Flags        = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
  441.     if (!GetOpenFileName(&ofn)) goto bail;
  442.  
  443.     // Create the child movie window
  444.     dwVersion = GetVersion();
  445.     gWeAreCreatingWindow = TRUE;
  446.     if ((dwVersion < 0x80000000) || (LOBYTE(LOWORD(dwVersion)) < 4))
  447.     {
  448.         // This is Windows NT or Win32s, so use the WM_MDICREATE message
  449.         MDICREATESTRUCT mcs;
  450.  
  451.         mcs.szClass = szChildName;
  452.         mcs.szTitle = szFileName; 
  453.         mcs.hOwner  = ghInst;
  454.         mcs.x       = CW_USEDEFAULT;
  455.         mcs.y       = CW_USEDEFAULT;
  456.         mcs.cx      = CW_USEDEFAULT;
  457.         mcs.cy      = CW_USEDEFAULT;
  458.         mcs.style   = 0;
  459.         mcs.lParam  = 0;
  460.  
  461.         hwndChild = (HWND) SendMessage(ghWndMDIClient,
  462.                                        WM_MDICREATE,
  463.                                        0,
  464.                                        (LPARAM)(LPMDICREATESTRUCT) &mcs);
  465.     }
  466.     else
  467.     {
  468.         // This method will only work with Windows 95, not Windows NT or Win32s
  469.         hwndChild = CreateWindowEx(WS_EX_MDICHILD,
  470.                                    szChildName,
  471.                                    szFileName,
  472.                                    0,
  473.                                    CW_USEDEFAULT,
  474.                                    CW_USEDEFAULT,
  475.                                    CW_USEDEFAULT,
  476.                                    CW_USEDEFAULT,
  477.                                    ghWndMDIClient, 
  478.                                    NULL,
  479.                                    ghInst,
  480.                                    0);
  481.     }
  482.     gWeAreCreatingWindow = FALSE;
  483.     if (!hwndChild) goto bail;
  484.  
  485.     MacSetPort(GetHWNDPort(hwndChild));
  486.     hStorage = (ChildWindowHand)GetWindowLong(hwndChild, GWL_USERDATA);
  487.  
  488.     // Set the window title to the movie filename
  489.     len = strlen(szPathName);
  490.     while (len--)
  491.     {
  492.         char    c = szPathName[len];
  493.         if (c == 0x5c || c == '/')
  494.         {
  495.             strcpy(szFileName, &szPathName[len+1]);
  496.             break;
  497.         }
  498.     }
  499.     SetWindowText(hwndChild, szFileName);
  500.  
  501.     // Open up the movie file...
  502.  
  503.     // Fill in a FSSpec.  Currently the vRefNum and parID are not used under Windows.
  504.     // Note the name must be a full pathname P-string!
  505.     fileSpec.vRefNum = 0;
  506.     fileSpec.parID = 0;
  507.     strcpy((char*)&fileSpec.name[1], szPathName);
  508.     fileSpec.name[0] = strlen(szPathName);
  509.     err = OpenMovieFile(&fileSpec, &movieRefNum, fsRdWrPerm);
  510.     if (err)
  511.         err = OpenMovieFile(&fileSpec, &movieRefNum, fsRdPerm);
  512.     if (!err)
  513.     {
  514.         movieResId = 0;
  515.         err = NewMovieFromFile(&theMovie, movieRefNum, &movieResId, NULL,newMovieActive,NULL);
  516.     }
  517.     if (err) goto bail;
  518.  
  519.     // Offset the movie box to (0,0)
  520.     GetMovieBox(theMovie, &movieBounds);
  521.     movieBounds.right = RECT_WIDTH(movieBounds);
  522.     movieBounds.bottom = RECT_HEIGHT(movieBounds);
  523.     movieBounds.left = movieBounds.top = 0;
  524.     
  525.     // Audio only movies need some width for the controller!
  526.     if (!movieBounds.right) movieBounds.right = 320;
  527.     SetMovieBox(theMovie, &movieBounds);
  528.  
  529.     // Create and initialize the movie controller
  530.     movieBounds.bottom += kMovieControllerHeight;
  531.     theMC = NewMovieController(theMovie, &movieBounds, mcTopLeftMovie);
  532.     if (!theMC) goto bail;
  533.  
  534.     MCDoAction(theMC, mcActionGetFlags, &mcFlags);
  535.     mcFlags |= (mcFlagSuppressMovieFrame | mcFlagsUseWindowPalette);
  536.     MCDoAction(theMC, mcActionSetFlags, (void*)mcFlags);
  537.     MCEnableEditing(theMC, true);
  538.  
  539.     // Make a growbox
  540.     // Set the mc resize bounds
  541.     hWndDesktop = GetDesktopWindow();
  542.     GetWindowRect(hWndDesktop, &rcWindow);
  543.     gMCResizeBounds.right = (short)rcWindow.right;
  544.     gMCResizeBounds.bottom = (short)rcWindow.bottom;
  545.     gMCResizeBounds.top = 48+16;            // Min height + mc
  546.     gMCResizeBounds.left = (16+16+16);    // Speaker+mc+grow icon widths
  547.     if (gMCResizeBounds.left < GetSystemMetrics(SM_CXMINTRACK))
  548.         gMCResizeBounds.left = GetSystemMetrics(SM_CXMINTRACK);
  549.     if (gMCResizeBounds.top < GetSystemMetrics(SM_CYMINTRACK))
  550.         gMCResizeBounds.top = GetSystemMetrics(SM_CYMINTRACK);
  551.     MCDoAction(theMC, mcActionSetGrowBoxBounds, &gMCResizeBounds);
  552.  
  553.     // Allow the controller to accept keyboard events
  554.     MCDoAction(theMC, mcActionSetKeysEnabled, (void*)1);
  555.  
  556.     // Store movie info in private window record
  557.     (**hStorage).m = theMovie;
  558.     (**hStorage).mc = theMC;
  559.     (**hStorage).resID = movieResId;
  560.     (**hStorage).refNum = movieRefNum;
  561.  
  562.     // Set a player filter proc to trap certain events
  563.     MCSetActionFilterWithRefCon(theMC, MyPlayerFilter, (long)hStorage);
  564.  
  565.     // Size the window to fit the movie and controller
  566.     SizeWindowToMovie(hwndChild);
  567.  
  568.     // Show the window
  569.     ShowWindow(hwndChild, SW_SHOW);
  570.     UpdateWindow(hwndChild);
  571.     SetFocus(hwndChild);
  572.  
  573.  
  574.     // One more window has been opened
  575.     cOpen += 1;
  576.  
  577.     return TRUE;
  578.  
  579. bail:
  580.     if (hwndChild) SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0L);
  581.     if (theMovie) DisposeMovie(theMovie);
  582.     if (theMC) DisposeMovieController(theMC);
  583.     return FALSE;
  584. }
  585.  
  586. /* ------------------------------------------------------------- */
  587.  
  588. static void DoCut(HWND hwnd)
  589. {
  590.     MovieController    mc = 0;
  591.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);
  592.  
  593.     if (hStorage)
  594.     {
  595.         if (mc = (**hStorage).mc)
  596.         {
  597.             // Cut the segment
  598.             Movie    scrapMovie = MCCut(mc);
  599.  
  600.             // Place the segment into the scrap
  601.             if (scrapMovie)
  602.             {
  603.                 PutMovieOnScrap(scrapMovie, 0L);
  604.                 DisposeMovie(scrapMovie);
  605.             }
  606.         }
  607.     }
  608. }
  609.  
  610. /* ------------------------------------------------------------- */
  611.  
  612. static void DoCopy(HWND hwnd)
  613. {
  614.     MovieController    mc = 0;
  615.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);
  616.  
  617.     if (hStorage)
  618.     {
  619.         if (mc = (**hStorage).mc)
  620.         {
  621.             // Copy the segment
  622.             Movie    scrapMovie = MCCopy(mc);
  623.  
  624.             // Place the segment into the scrap
  625.             if (scrapMovie)
  626.             {
  627.                 PutMovieOnScrap(scrapMovie, 0L);
  628.                 DisposeMovie(scrapMovie);
  629.             }
  630.         }
  631.     }
  632. }
  633.  
  634. /* ------------------------------------------------------------- */
  635.  
  636. static void DoPaste(HWND hwnd)
  637. {
  638.     MovieController    mc = 0;
  639.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);
  640.  
  641.     if (hStorage)
  642.     {
  643.         if (mc = (**hStorage).mc)
  644.             MCPaste(mc, nil);
  645.     }
  646. }
  647.  
  648. /* ------------------------------------------------------------- */
  649.  
  650. static void DoClear(HWND hwnd)
  651. {
  652.     MovieController    mc = 0;
  653.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);
  654.  
  655.     if (hStorage)
  656.     {
  657.         if (mc = (**hStorage).mc)
  658.             MCClear(mc);
  659.     }
  660. }
  661.  
  662. /* ------------------------------------------------------------- */
  663.  
  664. static void DoUndo(HWND hwnd)
  665. {
  666.     MovieController    mc = 0;
  667.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);
  668.  
  669.     if (hStorage)
  670.     {
  671.         if (mc = (**hStorage).mc)
  672.             MCUndo(mc);
  673.     }
  674. }
  675.  
  676. /* ------------------------------------------------------------- */
  677.  
  678. // Size the HWND to exactly fit the movie and controller
  679. void SizeWindowToMovie(HWND hWnd)
  680. {
  681.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(hWnd, GWL_USERDATA);
  682.     Movie        theMovie = (**hStorage).m;
  683.     MovieController    mc = (**hStorage).mc;
  684.     CGrafPtr    wPort = (CGrafPtr)GetHWNDPort(hWnd);
  685.     Rect        movieBounds;
  686.  
  687.     gWeAreSizingWindow = TRUE;
  688.  
  689.     MCGetControllerBoundsRect(mc, &movieBounds);
  690.     if (!RECT_WIDTH(movieBounds))
  691.     {
  692.         movieBounds.left = 0;
  693.         movieBounds.right = 320;
  694.     }
  695.  
  696.     // Size our window
  697.     SizeWindow((WindowPtr)wPort, movieBounds.right, movieBounds.bottom, FALSE);
  698.  
  699.     gWeAreSizingWindow = FALSE;
  700.  
  701.     MacSetPort((GrafPtr)wPort);
  702. }
  703.  
  704. /* ------------------------------------------------------------- */
  705.  
  706. Boolean MyPlayerFilter(MovieController theController, short action, void *params, long refCon)
  707. {
  708. #define mcActionControllerSizeChanged 26
  709.     ChildWindowHand    hStorage;
  710.  
  711.     switch (action) {
  712.     case  mcActionControllerSizeChanged:
  713.         if ( (hStorage = (ChildWindowHand)refCon) ) {
  714.             SizeWindowToMovie((**hStorage).hWnd);
  715.         }
  716.         break;
  717.     }
  718.     return 0;
  719. }
  720.  
  721. /* ------------------------------------------------------------- */
  722.  
  723. int DoIdleMenus(HWND hWnd, HMENU hMenu)
  724. {
  725.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(hWnd, GWL_USERDATA);
  726.     MovieController    mc = 0;
  727.  
  728.     if (hStorage) mc = (**hStorage).mc;
  729.  
  730.     // Enable the close item if there are any movie windows opened
  731.     EnableMenuItem(hMenu, IDM_FILECLOSE, (cOpen) ? MF_ENABLED : MF_GRAYED);
  732.  
  733.     // Idle the edit menu
  734.     if (mc)
  735.     {
  736.         long    controllerFlags;
  737.  
  738.         MCGetControllerInfo(mc,&controllerFlags);
  739.  
  740.         EnableMenuItem(hMenu, IDM_EDITUNDO, controllerFlags & mcInfoUndoAvailable ? MF_ENABLED : MF_GRAYED);
  741.         EnableMenuItem(hMenu, IDM_EDITCUT, controllerFlags & mcInfoCutAvailable ? MF_ENABLED : MF_GRAYED);
  742.         EnableMenuItem(hMenu, IDM_EDITCOPY, controllerFlags & mcInfoCopyAvailable ? MF_ENABLED : MF_GRAYED);
  743.         EnableMenuItem(hMenu, IDM_EDITPASTE, controllerFlags & mcInfoPasteAvailable ? MF_ENABLED : MF_GRAYED);
  744.         EnableMenuItem(hMenu, IDM_EDITCLEAR, controllerFlags & mcInfoClearAvailable ? MF_ENABLED : MF_GRAYED);
  745.     }
  746.  
  747.     return 0;
  748. }
  749.  
  750. /* ------------------------------------------------------------- */
  751.  
  752. static LRESULT CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  753. {
  754.     switch (message) {
  755.         case WM_COMMAND:
  756.             switch (LOWORD(wParam))
  757.             {
  758.                 case IDOK:
  759.                     EndDialog(hDlg, IDOK);
  760.                     break;
  761.             }
  762.             break;
  763.     }
  764.  
  765.     return 0;
  766. }
  767.  
  768. static void DoAbout()
  769. {
  770.     DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUT), ghWnd, (DLGPROC)DialogProc);
  771. }
  772.  
  773. /* ------------------------------------------------------------- */
  774.  
  775. // Get width of the window (vertical) borders
  776. static long GetWindowBorderWidth(HWND hWnd)
  777. {
  778.     RECT    rcWindow, rcClient;
  779.     
  780.     GetWindowRect(hWnd, &rcWindow);
  781.     GetClientRect(hWnd, &rcClient);
  782.  
  783.     return RECT_WIDTH(rcWindow) - RECT_WIDTH(rcClient);
  784. }
  785.  
  786. /* ------------------------------------------------------------- */
  787.  
  788. // Get height of the menubar contained by this window
  789. static long GetWindowMenuHeight(HWND hWnd)
  790. {
  791.     RECT    rcWindow, rcClient;
  792.     
  793.     GetWindowRect(hWnd, &rcWindow);
  794.     GetClientRect(hWnd, &rcClient);
  795.  
  796.     // Our MDI child windows have no menu
  797.     return (RECT_HEIGHT(rcWindow) - RECT_HEIGHT(rcClient)) - GetSystemMetrics(SM_CYCAPTION);
  798. }
  799.  
  800. /* ------------------------------------------------------------- */
  801.  
  802. static void CalcWindowMinMaxInfo(HWND theWnd, LPMINMAXINFO lpMinMax)
  803. {
  804.     ChildWindowHand    hStorage = (ChildWindowHand)GetWindowLong(theWnd, GWL_USERDATA);
  805.     MovieController    mc = 0;
  806.     Movie    m = 0;
  807.  
  808.     if (hStorage)
  809.     {
  810.         mc = (**hStorage).mc;
  811.         m = (**hStorage).m;
  812.     }
  813.  
  814.     if (mc && m)
  815.     {
  816.         Rect    movieBox;
  817.  
  818.         lpMinMax->ptMinTrackSize.x = gMCResizeBounds.left + (2 * GetSystemMetrics(SM_CXFRAME));
  819.         GetMovieBox(m, &movieBox);
  820.         if (RECT_HEIGHT(movieBox))
  821.             lpMinMax->ptMinTrackSize.y = gMCResizeBounds.top +    // growbounds height +
  822.                 (2 * GetSystemMetrics(SM_CXFRAME)) +            // frame wthickness +
  823.                 GetSystemMetrics(SM_CYCAPTION) +                // caption height +
  824.                 -1 +                                            // fudge factor
  825.                 kMovieControllerHeight;                            // movie controller height
  826.         else
  827.             lpMinMax->ptMaxSize.y =
  828.             lpMinMax->ptMaxTrackSize.y =
  829.             lpMinMax->ptMinTrackSize.y = 0 +                    // height of audio only movie +
  830.                 (2 * GetSystemMetrics(SM_CXFRAME)) +            // frame wthickness +
  831.                 GetSystemMetrics(SM_CYCAPTION) +                // caption height +
  832.                 -1 +                                            // fudge factor
  833.                 kMovieControllerHeight;                            // movie controller height
  834.     }
  835. }
  836.